import { keys, trim } from "lodash-es";
import { DomUtils } from 'htmlparser2'
import { ignoredAttrs } from "./attrs";
import util, { WxAppTemplate, dom, getOuterHTML, style } from "../util";
import { type Element, type Node } from "../util/dom";

const renameTags = [
    'ui-page',
    'ui-view',
    'ui-scroll-view',
    'ui-swiper',
    'ui-swiper-item',
    'ui-image',
    'ui-text',
    'ui-rich-text',
    'ui-progress',
    'ui-button',
    'ui-checkbox-group',
    'ui-checkbox',
    'ui-form',
    'ui-input',
    'ui-label',
    'ui-picker',
    'ui-picker-view',
    'ui-radio-group',
    'ui-radio',
    'ui-switch',
    'ui-textarea',
    'ui-navigator',
    'ui-audio',
    'ui-image',
    'ui-video',
    'ui-map'
];

const attrToStyleTags = ['ui-scroll-view', 'ui-image'];
const adjustmentTags = [
    'ui-input',
    'ui-text',
    'ui-rich-text',
    'ui-progress',
    'ui-checkbox',
    'ui-picker',
    'ui-radio',
    'ui-switch'
];

const wxForAssists = [
    'wx:for-item',
    'wx:for-index',
    'wx:key'
];


export class UiTemplate {
    dom!: Node[];
    directiveElems!: Element[];
    attrToStyleElems!: Element[];
    bindEventsElems!: Element[];
    styleElems!: Element[];
    customStyleElems!: Element[];
    wechatIconElems!: Element[];
    adjustmentElems!: Element[];
    renameElems!: any[];

    constructor(public source: string, public isApp?: Boolean | undefined) {
        this.initDom();
    }
    initDom() {
        if (!this.source)
            return;
        this.dom = dom.make(this.source);
        this.directiveElems = dom.getElementsByAttrRegex(this.dom, /^ui:/);
        this.attrToStyleElems = DomUtils.getElementsByTagName((name: string) => {
            return attrToStyleTags.indexOf(name) > -1;
        }, this.dom, true);
        this.bindEventsElems = dom.getElementsByAttrRegex(this.dom, /^bind/, /^\w+\((.*)\)/);
        this.styleElems = dom.getElementsByAttrRegex(this.dom, /^style$/);
        this.customStyleElems = dom.getElementsByAttrRegex(this.dom, /-style/);
        this.wechatIconElems = dom.getElementsByAttrRegex(this.dom, /^mode$/, /^wechat$/);
        this.adjustmentElems = dom.getElementsByTagName(this.dom, adjustmentTags);
        this.renameElems = dom.getElementsByTagName(this.dom, renameTags);
    }
    async generator() {
        let code = '';
        if (!this.dom)
            return code;
        if (this.isApp) {
            return WxAppTemplate;
        }
        this.transformUiDirective();
        this.transformAttrToStyle();
        this.transformEventArgs();
        this.transformBraceStyle();
        this.transformIcons();
        this.adjustAttrs();
        this.transformUiTag2WxTag();
        code = getOuterHTML(this.dom);
        return code;
    }
    transformUiDirective() {
        this.directiveElems.forEach((elem) => {
            Object.keys(elem.attribs).forEach((key) => {
                let value = elem.attribs[key];
                let newKey;
                let change = true;
                if (key === 'ui:model') {
                    if (['ui-popup', 'ui-mask'].indexOf(elem.name) > -1) {
                        newKey = 'show';
                    }
                    else if (elem.name === 'ui-input') {
                        newKey = 'value';
                    }
                    else if (elem.name === 'ui-switch') {
                        newKey = 'checked';
                    }
                    value = util.getMustcacheValue(value);
                }
                else if (key === 'ui:show') {
                    newKey = 'hidden';
                    let match = value.match(/\{\{\s*(.*)\s*\}\}/);
                    if (match) {
                        if (match[1].startsWith('!')) {
                            value = `{{ ${match[1].substring(1)} }}`;
                        }
                        else {
                            value = /(\|\||&&|>=?|<=?|===?)/.test(match[1]) ? `{{ !(${match[1]}) }}` : `{{ !${match[1]} }}`;
                        }
                    }
                    else {
                        if (value[0].startsWith('!')) {
                            value = `{{ ${value.substring(1)} }}`;
                        }
                        else {
                            value = `{{ !${value} }}`;
                        }
                    }
                }
                else if (/^ui:/.test(key)) {
                    newKey = key.replace('ui:', 'wx:');
                    if (wxForAssists.indexOf(newKey) < 0) {
                        value = util.getMustcacheValue(value);
                    }
                }
                else {
                    change = false;
                }
                if (newKey && change) {
                    elem.attribs[newKey] = value;
                    delete elem.attribs[key];
                }
            });
        });
    }
    transformAttrToStyle() {
        this.attrToStyleElems.forEach((elem) => {
            let attribs = elem.attribs;
            if (!attribs.style) {
                attribs.style = '';
            }
            if (attribs.width) {
                attribs.style += `width: ${attribs.width}px;`;
                delete attribs.width;
            }
            if (attribs.height) {
                attribs.style += `height: ${attribs.height}px;`;
                delete attribs.height;
            }
            if (attribs.style === '') {
                delete attribs.style;
            }
        });
    }
    transformEventArgs() {
        this.bindEventsElems.forEach((elem) => {
            keys(elem.attribs).forEach((key: string) => {
                if (/^bind/.test(key)) {
                    let matches = elem.attribs[key].match(/^(\w+)\((.*)\)/);
                    if (matches && matches[2]) {
                        let args = matches[2].split(',').map((arg: string) => trim(arg));
                        args.forEach((arg: any, index: number) => {
                            elem.attribs['data-arg' + index] = `{{ ${args[index]} }}`;
                        });
                        elem.attribs[key] = matches[1];
                    }
                }
            });
        });
    }
    transformBraceStyle() {
        this.styleElems.forEach((elem) => {
            style.uiStyle2wxStyle(elem);
        });
        this.customStyleElems.forEach((elem) => {
            style.reviseBrace(elem);
        });
    }
    transformIcons() {
        this.wechatIconElems.forEach((elem) => {
            elem.name = 'icon';
            delete elem.attribs.mode;
        });
    }
    adjustAttrs() {
        this.adjustmentElems.forEach((elem) => {
            if (elem.name === 'ui-input' && elem.attribs.type === 'password') {
                elem.attribs.password = '';
                delete elem.attribs.type;
                return;
            }
            // @ts-ignore
            let attrs = ignoredAttrs.ui2wx[elem.name];
            keys(elem.attribs).forEach((attr: any) => {
                if (attrs?.indexOf(attr) > -1) {
                    delete elem.attribs[attr];
                }
            });
        });
    }
    transformUiTag2WxTag() {
        this.renameElems.forEach((elem) => {
            if (elem.name === 'ui-page') {
                elem.name = 'view';
            }
            else {
                elem.name = elem.name.replace('ui-', '');
            }
        });
    }
}
